import re
import semver


class VersionCondition:
    """Cargo.toml中的版本号。总体和semver类似，但构造函数接受2.0, 1, >=1这样semver库不支持的版本号。"""

    def __init__(self):
        # [下界, 上界], -1表示没有要求
        self.conditions: list[tuple[str, semver.Version, str]] = list()

    @staticmethod
    def from_version_str(version_str: str) -> "VersionCondition":
        ver_cond = VersionCondition()

        """从包括但不限于>=x.y.z, < a.b这样的字符串构造版本号。"""
        conditions = list(map(lambda x: x.strip(), version_str.split(",")))
        for cond in conditions:
            # (>|>=|<|<=|=|^|~)
            op = re.match(r"^(>|>=|<|<=|=|^|~)", cond)
            if op is not None and op.group():
                op = op.group()
            else:
                op = "^"

            major_ver_res = re.match(r"^[\D]*(\d+|\*)", cond)
            assert major_ver_res is not None
            major_ver = int(major_ver_res.group(1))
            other_ver = re.findall(r"\.(\d+|\*)", cond)
            full_ver = [
                major_ver,
                0 if (len(other_ver) < 1 or other_ver[0] == "*") else int(other_ver[0]),
                0 if (len(other_ver) < 2 or other_ver[1] == "*") else int(other_ver[1]),
            ]
            # semver版本号之后的一坨东西
            extra_info_idx = major_ver_res.end() + sum(
                map(lambda x: len(str(x)) + 1, other_ver)
            )
            extra_info: str = cond[extra_info_idx:]

            ver_cond.conditions.append(
                (op, semver.Version.parse(".".join(map(str, full_ver))), extra_info)
            )
        # print(ver_cond)
        return ver_cond

    def __repr__(self) -> str:
        text: str = "Ver("
        for each in self.conditions:
            text += f"{each[0]}{each[1]}{each[2]}, "
        text += ")"
        return text

    def can_be_satisfied_by(self, other: semver.Version, extra_info: str) -> bool:
        for each in self.conditions:
            match each[0]:
                case "^":
                    if each[1].major == 0 and each[1].minor == 0:
                        return (
                            other.major == 0
                            and other.minor == 0
                            and other.patch == each[1].patch
                        )
                    elif each[1].major == 0:
                        return (
                            other.major == 0
                            and other.minor == each[1].minor
                            and other.patch >= each[1].patch
                        )
                    else:
                        return (
                            other.major == each[1].major
                            and other.minor >= each[1].minor
                            and other.patch >= each[1].patch
                        )
                case "=":
                    return other == each[1] and extra_info == each[2]
                case ">":
                    return other > each[1] and extra_info == each[2]
                case ">=":
                    return other >= each[1] and extra_info == each[2]
                case "<":
                    return other < each[1] and extra_info == each[2]
                case "<=":
                    return other <= each[1] and extra_info == each[2]
                case _:
                    raise ValueError(f"Invalid operator: `{each[0]}`")
        return False

    # def __eq__(self, other: "RustCrateVer") -> bool:
    #     return (self.major, self.minor, self.patch) == (
    #         other.major,
    #         other.minor,
    #         other.patch,
    #     )

    # def __lt__(self, other: "RustCrateVer") -> bool:
    #     if self.major < other.major:
    #         return True
    #     elif self.major == other.major:
    #         if self.minor < other.minor:
    #             return True
    #         else:
    #             return self.patch < other.patch
    #     else:
    #         return False

    # def __le__(self, other: "RustCrateVer") -> bool:
    #     return self < other or self == other


if __name__ == "__main__":
    print(VersionCondition.from_version_str("0.11.0+wasi-snapshot-preview1"))
    print(VersionCondition.from_version_str("1.23.456"))
    print(VersionCondition.from_version_str("=1.23.456"))
    print(VersionCondition.from_version_str(">=1.23, < 2"))
